#include <QtGui>

#include "server/DmxClient.h"

#include "SimpleChannel.h"

#define SETTINGS_FILE "dmx.ini"
#define GetSettingsObject() QSettings settings(SETTINGS_FILE,QSettings::IniFormat);

class DmxChannel; /* impl in OutputWindow */
class PresetValue : public QStorableObject
{
	Q_OBJECT
	
	Q_PROPERTY(int value READ value WRITE setValue);
	Q_PROPERTY(bool ignore READ ignore WRITE setIgnore);
	
public:
	PresetValue(DmxChannel *chan, int val=255, bool flag=false)
		: m_channel(chan)
		, m_value(val)
		, m_ignore(flag)
		, m_idx(0)
		{}
	
	DmxChannel *channel() { return m_channel; }

	int effectiveValue(int masterValue);
	
	int value() { return m_value; }
	bool ignore() { return m_ignore; }

	WidgetHash widgets() { return m_widgets; }
	void setWidgets(WidgetHash hash) { m_widgets = hash; }
	
	int idx() { return m_idx; }
	void setIdx(int x) { m_idx=x; }

	static bool comparitor(PresetValue *a, PresetValue *b);
	
public slots:
	void setValue(int v) { m_value = v; emit valueChanged(v); }
	void setIgnore(bool flag) { m_ignore = flag; emit ignoreChanged(flag); }

signals:
	void valueChanged(int value);
	void ignoreChanged(bool flag);

private:
	DmxChannel *m_channel;
	int m_value;
	bool m_ignore;
	
	int m_idx;
	
	WidgetHash m_widgets;
	
	
};

typedef QList<PresetValue*> PresetValueList;

class LightingPreset : public SimpleChannel
{
	Q_OBJECT
	
public:
	LightingPreset(QString name="", int num=0)
		: SimpleChannel(name, num)
		{}
	
	const PresetValueList & values() { return m_values; }
	
	int effectiveValue(DmxChannel *chan);
	
	// From QStorableObject, overridden so we can store/retrieve the values() list
	virtual bool fromVariantMap(const QVariantMap&, bool onlyApplyIfChanged = false);
	virtual QVariantMap toVariantMap();
	
public slots:
	void setValues(const PresetValueList& list) { m_values = list; }
	
	virtual void setValue(int value);
	
protected:
	PresetValueList m_values;
};

class OutputWindow;
class PresetEditWindow;
class LightingServer;
class MainWindow : public QWidget
{
	Q_OBJECT
	
	Q_PROPERTY(int mainLevel READ mainLevel WRITE setMainLevel);
	
public:
	MainWindow();
	~MainWindow();
	
	static MainWindow *inst() { return mw; }
	
	DmxClient *dmxClient() { return m_dmxClient; }
	
	OutputWindow *outputWindow() { return m_outputWin; }
	
	bool isBlack() { return m_isBlack; }
	int mainLevel() { return m_mainLevel; }
	
	QList<LightingPreset*> presets() { return m_presets; } 
	
protected:
	void setupGui();
	bool initClient();
	void closeClient();
	
	void loadSettings();
	void saveSettings();
	
	void closeEvent(QCloseEvent*) { saveSettings(); }
	
public slots:
	void setFadeSpeed(int, bool temp=false); // integer 0-100 as a percent, from 0-10000 ms 
	
	void setMainLevel(int);
	void fadeBlack(bool);
	void toggleBlack() { fadeBlack(!isBlack()); }
	
	void playPreset(int preset, int endValue=-1); // -1 = auto
	void playPreset(LightingPreset *preset, int endValue=-1); // -1=auto
	void setPresetLevel(int preset, int level);
	
	void showMidiSettingsDialog();
	
signals:
	void mainLevelChanged(int);

private slots:
	void presetNumChanged(int num);
	void valueAnimFinished();
	
	void switchToggled(bool);

	void setWallSwitchEnabled(bool);
	
	void countdownExpires();
	void resetCountdown();
	
	void showOutputWindow();
	void addNewPreset();
	void addPreset(LightingPreset*);
	
	//void presetMenuButtonClicked();
	void presetPlayButtonClicked();
	void presetLevelChanged(int);
	void presetValueChanged(int);
	void presetEdit(LightingPreset *preset=0);
	void presetDelete();
	
	// TODO: Future implementation
	//void fadeModeComboChanged(int);

	void generateSliderUI();
	
	void storePresets();
	void loadPresets();
	
	void presetNameChanged(QString);
	
private:
	QMenu *createPresetMenu(LightingPreset*, QWidget *parent);
	
private:
	// DMX output interface
	DmxClient *m_dmxClient;
	
	// Last host/port - read/stored in QSettings
	QString m_host;
	int m_port;
	
	// Value of the "main" slider, used to augment the values sent (m_mainValue/255)*sentValue
	int m_mainLevel;
	QSlider *m_mainSlider;
	
	// Stores the flag to tell if mains are "black"s or not
	bool m_isBlack;
	QPushButton *m_blackButton;
	
	// Label to indicate status of switch
	QLabel *m_switchLabel;
	
	// True if GUI controls have given control of the lights to wall switch
	bool m_switchEnabled;
	
	// Pointer to button that gives control to the wall switch
	QRadioButton *m_wallControlButton;
	
	// Timer to expire interactive control and revert to wall switch
	QTimer m_expiresCountdownTimer;
	
	// Button pointer to counter reset - stored only so we can enable/disable it 
	QPushButton *m_resetCounterBtn;
	
	// Current minutes left until interactive control expires
	int m_countdownValue;
	
	// Label pointer to indicate current minutes remaining till control expires and reverts to switch
	QLabel *m_countdownLabel;
	
	// Parent for the present control widgets
	QGroupBox *m_controlWidgetBase;
	
	// Spinbox for fadespeed changes
	QSpinBox *m_fadeSpeedBox; 
	
	// GridLayout for the sliders
	QGridLayout *m_sliderGrid;
	
	// List of presets
	QList<LightingPreset*> m_presets;
	
	// Handles "main" values and main output control
	OutputWindow *m_outputWin;
	
	// Property anim to animate fade to/from black
	QPropertyAnimation *m_blackAnim;
	
	// Static instance so other classes can find our channel list via outputWindow()	
	static MainWindow *mw;
	
	// Store pointers to preset editor windows so we dont open duplicate edit windows for the same preset
	QHash<LightingPreset*, PresetEditWindow*> m_editWindows;
	
	// HTTP server to trigger presets via HTTP
	LightingServer *m_httpServer;
	 
	bool m_fadeSpeedIsTemp;
	int m_oldFadeSpeed;
};

